package com.chml.service.impl;

import com.chml.dto.*;
import com.chml.exception.FailCallException;
import com.chml.mapper.*;
import com.chml.params.AddMaternityParam;
import com.chml.params.DeleteMaternityParam;
import com.chml.params.MaternityListParam;
import com.chml.pojo.*;
import com.chml.service.EvaluationService;
import com.chml.service.MaternityService;
import com.chml.service.MediaDataService;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import net.sf.json.JSONObject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.json.JSONArray;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 实现与月嫂相关的数据库操作，包括月嫂信息的增删改查
 */
@Service("maternityService")
@Transactional
public class MaternityServiceImpl implements MaternityService {
    @Resource
    private MaternityMatronBaseInfoMapper maternityMatronBaseInfoMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private NursingExperienceMapper nursingExperienceMapper;
    @Resource
    private MediaDataMapper mediaDataMapper;
    @Resource
    private EvaluationMapper evaluationMapper;
    @Resource
    private MatronPostHospitalInfoMapper matronPostHospitalInfoMapper;
    @Resource
    private TrainingExperienceMapper trainingExperienceMapper;
    @Resource
    private MyMapper myMapper;
    @Resource
    private EvaluationService evaluationService;
    @Resource
    private MediaDataService mediaDataService;

    private static Logger logger = LogManager.getRootLogger();

    /**
     * 获取符合条件的月嫂列表
     *
     * @param filterInfo
     * @return
     * @throws Exception
     */
    public List<MaternityInfoDTO> getMaternityList(MaternityListParam filterInfo, String name) throws Exception {
        return myMapper.selectMaternityInfoByFilter(filterInfo, (filterInfo.getPage() - 1) * filterInfo.getPer_page(), "%" + name + "%");
    }

    /**
     * 获取数据库中的月嫂信息总数
     *
     * @return
     * @throws Exception
     */
    public int getMaternityListTotalCount() throws Exception {
        int count = maternityMatronBaseInfoMapper.getMaternityListTotalCount();
        return count;
    }

    /**
     * 获取符合条件的月嫂的总数
     *
     * @param filterInfo
     * @return
     * @throws Exception
     */
    public int getMaternityListCount(MaternityListParam filterInfo, String name) throws Exception {

        return myMapper.countMaternityInfoByFilter(filterInfo, "%" + name + "%");
    }

    /**
     * 批量删除月嫂
     *
     * @param idList
     * @throws Exception
     */
    public void deleteMaternity(DeleteMaternityParam idList) throws Exception {
        logger.debug("check access_token");
        int uid = idList.getUid();
        String access_token = idList.getAccess_token();
        User current_user = userMapper.selectByPrimaryKey(uid);
        if (current_user == null) {
            throw new Exception("当前用户不存在，请重新登录");
        }
        if (!current_user.getAccessToken().equals(access_token)) {
            throw new Exception("登录状态已失效,请重新登录");
        }

        for (int index = 0; index < idList.getId().size(); index++) {
            MaternityMatronBaseInfo maternityInfo = maternityMatronBaseInfoMapper.selectByPrimaryKey(idList.getId().get(index));
            logger.debug("delete grade data");
            evaluationService.deleteByMid(idList.getId().get(index));
            logger.debug("delete hospital data");
            matronPostHospitalInfoMapper.deleteByMid(idList.getId().get(index));
            logger.debug("delete media data");
            mediaDataMapper.deleteByMid(idList.getId().get(index));
            logger.debug("delete training data");
            trainingExperienceMapper.deleteByMid(idList.getId().get(index));
            maternityMatronBaseInfoMapper.deleteByPrimaryKey(idList.getId().get(index));
            logger.debug("delete nursing data");
            nursingExperienceMapper.deleteByPrimaryKey(maternityInfo.getNid());
        }
    }

    /**
     * 获取某个月嫂的详细信息
     *
     * @param id
     * @param uid
     * @param access_token
     * @return
     * @throws Exception
     */
    public MaternityDetailDTO getMaternityDetail(int id, int uid, String access_token) throws Exception {
        logger.debug("check access_token");
        User current_user = userMapper.selectByPrimaryKey(uid);
        if (current_user == null) {
            throw new Exception("当前用户不存在，请重新登录");
        }
        if (!current_user.getAccessToken().equals(access_token)) {
            throw new Exception("登录状态已失效,请重新登录");
        }
        //get data from database
        MaternityMatronBaseInfo baseInfo = maternityMatronBaseInfoMapper.selectByPrimaryKey(id);
        if (baseInfo == null) {
            throw new Exception("月嫂不存在，删除错误");
        }
        String intro_video_url = mediaDataMapper.selectVideoUrlByMid(id);
        GradeInfo grade = new GradeInfo();
        int oneCount = evaluationService.getGradeCount(baseInfo.getMid(),1);
        int twoCount = evaluationService.getGradeCount(baseInfo.getMid(),2);
        int threeCount = evaluationService.getGradeCount(baseInfo.getMid(),3);
        int fourCount = evaluationService.getGradeCount(baseInfo.getMid(),4);
        int fiveCount = evaluationService.getGradeCount(baseInfo.getMid(),5);
        grade.setOne(oneCount);
        grade.setTwo(twoCount);
        grade.setThree(threeCount);
        grade.setFour(fourCount);
        grade.setFive(fiveCount);

        MaternityDetailDTO retInfo = new MaternityDetailDTO();
        retInfo.setId(baseInfo.getMid());
        retInfo.setName(baseInfo.getName());
        retInfo.setAge(baseInfo.getAge());
        retInfo.setBirth_place(baseInfo.getNativePlace());
        retInfo.setPhone_num(baseInfo.getContactNumber());
        retInfo.setHead_img_url(baseInfo.getHeadImgUrl());
        retInfo.setIntro_video_url(intro_video_url);

        String language_data = baseInfo.getLanguage();
        String[] language_array = language_data.split(",");
        List<String> language_list = new ArrayList<>();
        for (int i = 0; i < language_array.length; i++) {
            language_list.add(language_array[i]);
        }
        retInfo.setLanguage(language_list);
        String[] mar_and_pro = baseInfo.getProcreationState().split(",");
        retInfo.setMarriageState(mar_and_pro[0]);
        retInfo.setProcreationState(mar_and_pro[1]);

        retInfo.setEmergencyContactPersonName(baseInfo.getEmergencyContactPersonName());
        retInfo.setEmergencyContactPersonRelation(baseInfo.getEmergencyContactPersonRelation());
        retInfo.setEmergencyContactPersonNumber(baseInfo.getEmergencyContactPersonNumber());
        retInfo.setEducationBackground(baseInfo.getEducationBackground());
        retInfo.setGrade(grade);
        retInfo.setCertificates(baseInfo.getCertificates());
        retInfo.setLevel(baseInfo.getLevel());
        return retInfo;
    }

    /**
     * 添加月嫂信息
     *
     * @param maternityInfo
     * @return
     * @throws Exception
     */
    public int addMaternity(AddMaternityParam maternityInfo) throws Exception {
        logger.debug("check access_token");
        int uid = maternityInfo.getUid();
        String access_token = maternityInfo.getAccess_token();
        User current_user = userMapper.selectByPrimaryKey(uid);
        if (current_user == null) {
            throw new Exception("当前用户不存在，请重新登录");
        }
        if (!current_user.getAccessToken().equals(access_token)) {
            throw new Exception("登录状态已失效,请重新登录");
        }

        logger.debug("insert nursing info to database");
        NursingExperience nursingExperience = new NursingExperience();
        nursingExperience.setEnterDate(maternityInfo.getCertificates().getNursing().getFirst_time());
        nursingExperience.setNumOfTwin(maternityInfo.getCertificates().getNursing().getNum_of_twins());
        nursingExperience.setExperience(maternityInfo.getCertificates().getNursing().getExperience());
        nursingExperience.setNumOfFamily(maternityInfo.getCertificates().getNursing().getNum_of_family());
        nursingExperience.setFamilyType(maternityInfo.getCertificates().getNursing().getFamily_type().toString());
        nursingExperience.setLocation(maternityInfo.getCertificates().getNursing().getLocation().toString());
        nursingExperienceMapper.insert(nursingExperience);
        int nid = nursingExperience.getNid();

        logger.debug("insert maternity_base_info to database");
        MaternityMatronBaseInfo baseInfo = new MaternityMatronBaseInfo();
        baseInfo.setName(maternityInfo.getName());
        baseInfo.setAge((byte) maternityInfo.getAge());
        baseInfo.setContactNumber(maternityInfo.getPhone_num());
        baseInfo.setNativePlace(maternityInfo.getBirth_place());
        baseInfo.setHeadImgUrl(maternityInfo.getHead_img_url());
        baseInfo.setLevel(maternityInfo.getLevel());
        baseInfo.setEducationBackground(maternityInfo.getEducationBackground());
        baseInfo.setEmergencyContactPersonName(maternityInfo.getEmergencyContactPersonName());
        baseInfo.setEmergencyContactPersonNumber(maternityInfo.getEmergencyContactPersonNumber());
        baseInfo.setEmergencyContactPersonRelation(maternityInfo.getEmergencyContactPersonRelation());
        baseInfo.setProcreationState(maternityInfo.getMarriageState() + "," + maternityInfo.getProcreationState());
        String language_data = "";
        if (maternityInfo.getLanguage().size() == 1) {
            language_data += maternityInfo.getLanguage().get(0);
        } else {
            for (int i = 0; i < maternityInfo.getLanguage().size(); i++) {
                if (i == 0) {
                    language_data += maternityInfo.getLanguage().get(0);
                } else {
                    language_data += "," + maternityInfo.getLanguage().get(i);
                }
            }
        }
        baseInfo.setLanguage(language_data);
        Map<String, Object> certificate_json = new HashMap<>();
        certificate_json.put("id_card", maternityInfo.getCertificates().getId_card());
        certificate_json.put("health", maternityInfo.getCertificates().getHealth());
        certificate_json.put("skills", maternityInfo.getCertificates().getSkills());
        certificate_json.put("training", maternityInfo.getCertificates().getTraining());
        certificate_json.put("nursing", maternityInfo.getCertificates().getNursing());
        certificate_json.put("working_photo", maternityInfo.getCertificates().getWorking_photo());
        JSONArray array = new JSONArray();
        array.put(certificate_json);
        baseInfo.setCertificates(array.toString());
        baseInfo.setNid(nid);
        maternityMatronBaseInfoMapper.insert(baseInfo);
        int mid = baseInfo.getMid();

        logger.debug("insert hospital info to database");
        List<String> hospitalList = maternityInfo.getCertificates().getTraining().getHospital();
        for (int i = 0; i < hospitalList.size(); i++) {
            MatronPostHospitalInfo matronPostHospitalInfo = new MatronPostHospitalInfo();
            matronPostHospitalInfo.setMid(mid);
            matronPostHospitalInfo.setHid(13);//TODO
            matronPostHospitalInfo.setGrade("优秀");//TODO
            matronPostHospitalInfo.setImg("matronPostHospitalInfo.jpg");//TODO
            matronPostHospitalInfoMapper.insert(matronPostHospitalInfo);
        }

        logger.debug("insert training info to database");
        List<String> subjectList = maternityInfo.getCertificates().getTraining().getSubjects();
        for (int i = 0; i < subjectList.size(); i++) {
            TrainingExperience trainingExperience = new TrainingExperience();
            trainingExperience.setMid(mid);
            trainingExperience.setImg("training.jpg");//TODO
            trainingExperience.setGrade("优秀");//TODO
            trainingExperience.setInstitution("华山医院");//TODO
            trainingExperience.setName(subjectList.get(i));
            trainingExperienceMapper.insert(trainingExperience);
        }

        logger.debug("insert video url to database");
        MediaData mediaData = new MediaData();
        mediaData.setMid(mid);
        mediaData.setType(1);
        mediaData.setUrl(maternityInfo.getIntro_video_url());
        mediaDataMapper.insert(mediaData);

        return mid;
    }

    /**
     * 更新数据库中的月嫂信息
     *
     * @param mid
     * @param maternityInfo
     * @return
     * @throws Exception
     */
    public int updateMaternity(int mid, AddMaternityParam maternityInfo) throws Exception {
        logger.debug("check access_token");
        int uid = maternityInfo.getUid();
        String access_token = maternityInfo.getAccess_token();
        User current_user = userMapper.selectByPrimaryKey(uid);
        if (current_user == null) {
            throw new Exception("当前用户不存在，请重新登录");
        }
        if (!current_user.getAccessToken().equals(access_token)) {
            throw new Exception("登录状态已失效,请重新登录");
        }

        logger.debug("update maternity base info");
        MaternityMatronBaseInfo baseInfo = maternityMatronBaseInfoMapper.selectByPrimaryKey(mid);
        //baseInfo.setMid(mid);
        baseInfo.setName(maternityInfo.getName());
        baseInfo.setAge((byte) maternityInfo.getAge());
        baseInfo.setContactNumber(maternityInfo.getPhone_num());
        baseInfo.setNativePlace(maternityInfo.getBirth_place());
        baseInfo.setHeadImgUrl(maternityInfo.getHead_img_url());
        baseInfo.setLevel(maternityInfo.getLevel());
        baseInfo.setEducationBackground(maternityInfo.getEducationBackground());
        baseInfo.setEmergencyContactPersonName(maternityInfo.getEmergencyContactPersonName());
        baseInfo.setEmergencyContactPersonNumber(maternityInfo.getEmergencyContactPersonNumber());
        baseInfo.setEmergencyContactPersonRelation(maternityInfo.getEmergencyContactPersonRelation());
        baseInfo.setProcreationState(maternityInfo.getProcreationState());
        baseInfo.setProcreationState(maternityInfo.getMarriageState() + "," + maternityInfo.getProcreationState());
        String language_data = "";
        if (maternityInfo.getLanguage().size() == 1) {
            language_data += maternityInfo.getLanguage().get(0);
        } else {
            for (int i = 0; i < maternityInfo.getLanguage().size(); i++) {
                if (i == 0) {
                    language_data += maternityInfo.getLanguage().get(0);
                } else {
                    language_data += "," + maternityInfo.getLanguage().get(i);
                }
            }
        }
        baseInfo.setLanguage(language_data);
        Map<String, Object> certificate_json = new HashMap<>();
        certificate_json.put("id_card", maternityInfo.getCertificates().getId_card());
        certificate_json.put("health", maternityInfo.getCertificates().getHealth());
        certificate_json.put("skills", maternityInfo.getCertificates().getSkills());
        certificate_json.put("training", maternityInfo.getCertificates().getTraining());
        certificate_json.put("nursing", maternityInfo.getCertificates().getNursing());
        certificate_json.put("working_photo", maternityInfo.getCertificates().getWorking_photo());
        JSONArray array = new JSONArray();
        array.put(certificate_json);
        baseInfo.setCertificates(array.toString());
        //System.out.println("Certificates = " + array.toString());
        maternityMatronBaseInfoMapper.updateByPrimaryKeyWithBLOBs(baseInfo);

        logger.debug("update nursing data");
        int nid = baseInfo.getNid();
        NursingExperience nursingExperience = nursingExperienceMapper.selectByPrimaryKey(nid);
        nursingExperience.setEnterDate(maternityInfo.getCertificates().getNursing().getFirst_time());
        nursingExperience.setNumOfTwin(maternityInfo.getCertificates().getNursing().getNum_of_twins());
        nursingExperience.setExperience(maternityInfo.getCertificates().getNursing().getExperience());
        nursingExperience.setNumOfFamily(maternityInfo.getCertificates().getNursing().getNum_of_family());
        nursingExperience.setFamilyType(maternityInfo.getCertificates().getNursing().getFamily_type().toString());
        nursingExperience.setLocation(maternityInfo.getCertificates().getNursing().getLocation().toString());
        nursingExperienceMapper.updateByPrimaryKey(nursingExperience);

        logger.debug("update video url");
        MediaData media = mediaDataMapper.selectMediaDataByMid(mid);
        if (media == null) {
            media = new MediaData();
            media.setUrl(maternityInfo.getIntro_video_url());
            media.setMid(mid);
            media.setType(1);
            mediaDataMapper.insert(media);
        }
        else {
            media.setUrl(maternityInfo.getIntro_video_url());
            mediaDataMapper.updateByPrimaryKey(media);
        }
        return 0;
    }

    @Override
    public MaternityBaseInfo getBaseInfo(int mid) throws Exception{
        MaternityBaseInfo maternityBaseInfo = new MaternityBaseInfo();
        MaternityMatronBaseInfo maternityMatronBaseInfo = maternityMatronBaseInfoMapper.selectByPrimaryKey(mid);
        if (maternityMatronBaseInfo == null) {
            throw new FailCallException("没有该月嫂",201);
        }
        maternityBaseInfo.setName(maternityMatronBaseInfo.getName());
        maternityBaseInfo.setAge(maternityMatronBaseInfo.getAge());
        maternityBaseInfo.setLevel(maternityMatronBaseInfo.getLevel());
        maternityBaseInfo.setEducation(maternityMatronBaseInfo.getEducationBackground());
        maternityBaseInfo.setBirthPlace(maternityMatronBaseInfo.getNativePlace());
        maternityBaseInfo.setHeadImgUrl(maternityMatronBaseInfo.getHeadImgUrl());
        maternityBaseInfo.setPhone(maternityMatronBaseInfo.getContactNumber());

        maternityBaseInfo.setIntroVideoUrl(mediaDataMapper.selectVideoUrlByMid(mid));

        return maternityBaseInfo;
    }

    @Override
    public List<CertificateDto> getCertificates(int mid) throws IOException {
        List<CertificateDto> certificates = new ArrayList<>();
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode rootNode = objectMapper.readTree(maternityMatronBaseInfoMapper.selectByPrimaryKey(mid).getCertificates()).path(0);
        ArrayNode skills = (ArrayNode) rootNode.path("skills");
        String[] skillLevel = {"高级技师","技师","高级","中级","初级"};
        if (!skills.isMissingNode()) {
            for (int i=0;i<skills.size();i++) {
                CertificateDto certificate = new CertificateDto();
                certificate.setName(skills.get(i).path("name").asText());
                int level = skills.get(i).path("level").asInt();
                if (level>0&&level<=5) {
                    certificate.setLevel(skillLevel[level-1]);
                }
                certificate.setImgUrl(skills.get(i).path("img_url").asText());
                certificate.setNumber(skills.get(i).path("sn").asText());
                certificates.add(certificate);
            }
        }
        return certificates;
    }

    @Override
    public List<WorkingPhotoInfo> getWorkingPhoto(int mid) throws IOException {
        List<WorkingPhotoInfo> workingPhotoInfos = new ArrayList<>();
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode rootNode = objectMapper.readTree(maternityMatronBaseInfoMapper.selectByPrimaryKey(mid).getCertificates()).path(0);
        ArrayNode workingPhotos = (ArrayNode) rootNode.path("working_photo");
        if (!workingPhotos.isMissingNode()) {
            for (int i=0;i<workingPhotos.size();i++) {
                workingPhotoInfos.add(objectMapper.readValue(workingPhotos.get(i).toString(), WorkingPhotoInfo.class));
            }
        }
        return workingPhotoInfos;
    }

    @Override
    public List<String> getPostHospitals(int mid) throws IOException, FailCallException {
        try {
            String temp = maternityMatronBaseInfoMapper.selectByPrimaryKey(mid).getCertificates();
            temp = temp.substring(1, temp.length() - 1);
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode rootNode = objectMapper.readTree(temp);
            TrainingInfo trainingInfo = objectMapper.readValue(rootNode.get("training").toString(),TrainingInfo.class);
            return trainingInfo.getHospital();
        } catch (NullPointerException e) {
            throw new FailCallException("没有该月嫂",201);
        }
    }

    @Override
    public List<String> getTrainingSubjects(int mid) throws IOException, FailCallException {
        try {
            String temp = maternityMatronBaseInfoMapper.selectByPrimaryKey(mid).getCertificates();
            temp = temp.substring(1, temp.length() - 1);
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode rootNode = objectMapper.readTree(temp);
            TrainingInfo trainingInfo = objectMapper.readValue(rootNode.get("training").toString(),TrainingInfo.class);
            return trainingInfo.getSubjects();
        } catch (NullPointerException e) {
            throw new FailCallException("没有该月嫂",201);
        }
    }

    public int getNursingExperienceByNid(int nid) throws Exception {
        NursingExperience nursingExperience = nursingExperienceMapper.selectByPrimaryKey(nid);

        /*Date start_nursing_date = nursingExperience.getEnterDate();
        Calendar start_nursing_cal = Calendar.getInstance();
        start_nursing_cal.setTime(start_nursing_date);
        int start_nursing_year = start_nursing_cal.get(Calendar.YEAR);
        start_nursing_cal.setTime(new Date());
        int now_year = start_nursing_cal.get(Calendar.YEAR);

        return (now_year - start_nursing_year);*/
        return nursingExperience.getExperience();
    }
}
